/**
 * @file   BalanceTree.h
 * @author Linfufu
 * @date   Tue Nov 23 16:53:56 2021
 * 
 * @brief  
 * 
 * 
 */
#ifndef AVL_TREE_H
#define AVL_TREE_H

#include<bits/stdc++.h>
using namespace std;

template <typename Comparable>
class AvlTree
{
public:
    AvlTree( ) : root{ nullptr }
	{ }
    
    AvlTree( const AvlTree & rhs ) : root{ nullptr }
    {
        root = clone( rhs.root );
    }

    AvlTree( AvlTree && rhs ) : root{ rhs.root }
    {
        rhs.root = nullptr;
    }
    
    ~AvlTree( )
    {
        makeEmpty( );
    }

    /**
     * Deep copy.
     */
    AvlTree & operator=( const AvlTree & rhs )
    {
        AvlTree copy = rhs;
        std::swap( *this, copy );
        return *this;
    }
        
    /**
     * Move.
     */
    AvlTree & operator=( AvlTree && rhs )
    {
        std::swap( root, rhs.root );
        
        return *this;
    }
    
    /**
     * Find the smallest item in the tree.
     * 
     */
    const Comparable & findMin( ) const
    {
        if( !isEmpty( ) )
	  findMin( root )->element;
    }

    /**
     * Find the largest item in the tree.
     * 
     */
    const Comparable & findMax( ) const
    {
        if( !isEmpty( ) )
	  findMax( root )->element;
    }

    /**
     * Returns true if x is found in the tree.
     */
    bool contains( const Comparable & x ) const
    {
        return contains( x, root );
    }

    /**
     * Test if the tree is logically empty.
     * Return true if empty, false otherwise.
     */
    bool isEmpty( ) const
    {
        return root == nullptr;
    }

    /**
     * Print the tree contents in sorted order.
     */
    void printTree( ) const
    {
        if( isEmpty( ) )
            cout << "Empty tree" << endl;
        else
            printTree( root );
    }

    /**
     * Make the tree logically empty.
     */
    void makeEmpty( )
    {
        makeEmpty( root );
    }

    /**
     * Insert x into the tree; duplicates are ignored.
     */
    void insert( const Comparable & x )
    {
        insert( x, root );
    }
     
    /**
     * Insert x into the tree; duplicates are ignored.
     */
    void insert( Comparable && x )
    {
        insert( std::move( x ), root );
    }
     
    /**
     * Remove x from the tree. Nothing is done if x is not found.
     */
    void remove( const Comparable & x )
    {
        remove( x, root );
    }

private:
    struct AvlNode
    {
        Comparable element;
        AvlNode   *left;
        AvlNode   *right;
        int       height;

        AvlNode( const Comparable & ele, AvlNode *lt, AvlNode *rt, int h = 0 )
      	: element{ ele }, left{ lt }, right{ rt }, height{ h } { }
        
        AvlNode( Comparable && ele, AvlNode *lt, AvlNode *rt, int h = 0 )
      	: element{ std::move( ele ) }, left{ lt }, right{ rt }, height{ h } { }
    };

    AvlNode *root;


    /**
     * Internal method to insert into a subtree.
     * x is the item to insert.
     * t is the node that roots the subtree.
     * Set the new root of the subtree.
     */
    void insert( const Comparable & x, AvlNode * & t )
    {
        if( t == nullptr )
            t = new AvlNode{ x, nullptr, nullptr };
        else if( x < t->element )
            insert( x, t->left );
        else if( t->element < x )
            insert( x, t->right );
        
        balance( t );
    }

    /**
     * Internal method to insert into a subtree.
     * x is the item to insert.
     * t is the node that roots the subtree.
     * Set the new root of the subtree.
     */
    void insert( Comparable && x, AvlNode * & t )
    {
        if( t == nullptr )
            t = new AvlNode{ std::move( x ), nullptr, nullptr };
        else if( x < t->element )
            insert( std::move( x ), t->left );
        else if( t->element < x )
            insert( std::move( x ), t->right );
        
        balance( t );
    }
     
    /**
     * Internal method to remove from a subtree.
     * x is the item to remove.
     * t is the node that roots the subtree.
     * Set the new root of the subtree.
     */
    void remove( const Comparable & x, AvlNode * & t )
    {
        if( t == nullptr )
            return;   // Item not found; do nothing
        
        if( x < t->element )
            remove( x, t->left );
        else if( t->element < x )
            remove( x, t->right );
        else if( t->left != nullptr && t->right != nullptr ) // Two children
	  {
	    t->element = findMin( t->right )->element;
	    remove( t->element, t->right );
	  }
        else
	  {
	    AvlNode *oldNode = t;
	    t = ( t->left != nullptr ) ? t->left : t->right;
	    delete oldNode;
	  }
        
        balance( t );
    }
    
	/// 全局, 只读, 只在当前区域可见. 可以认为是对且只对所有类实体都起作用的常量. 
    static const int ALLOWED_IMBALANCE = 1;

    // Assume t is balanced or within one of being balanced
    void balance( AvlNode * & t )
    {
        if( t == nullptr )
            return;
        
        if( height( t->left ) - height( t->right ) > ALLOWED_IMBALANCE )
            if( height( t->left->left ) >= height( t->left->right ) )
                rotateWithLeftChild( t );
            else
                doubleWithLeftChild( t );
        else if( height( t->right ) - height( t->left ) > ALLOWED_IMBALANCE )
	  {
	    if( height( t->right->right ) >= height( t->right->left ) )
        	rotateWithRightChild( t );
	    else
	      doubleWithLeftChild(t);
	  }
        t->height = max( height( t->left ), height( t->right ) ) + 1;
    }
    
    /**
     * Internal method to find the smallest item in a subtree t.
     * Return node containing the smallest item.
     */
    AvlNode * findMin( AvlNode *t ) const
    {
        if( t == nullptr )
            return nullptr;
        if( t->left == nullptr )
            return t;
        return findMin( t->left );
    }

    /**
     * Internal method to find the largest item in a subtree t.
     * Return node containing the largest item.
     */
    AvlNode * findMax( AvlNode *t ) const
    {
        if( t != nullptr )
            while( t->right != nullptr )
                t = t->right;
        return t;
    }


    /**
     * Internal method to test if an item is in a subtree.
     * x is item to search for.
     * t is the node that roots the tree.
     */
    bool contains( const Comparable & x, AvlNode *t ) const
    {
        if( t == nullptr )
            return false;
        else if( x < t->element )
            return contains( x, t->left );
        else if( t->element < x )
            return contains( x, t->right );
        else
            return true;    // Match
    }

    /**
     * Internal method to make subtree empty.
     */
    void makeEmpty( AvlNode * & t )
    {
        if( t != nullptr )
        {
	   makeEmpty( t->left );
	   makeEmpty( t->right );
	   delete t;
        }
        t = nullptr;
    }

    /**
     * Internal method to print a subtree rooted at t in sorted order.
     */
    void printTree( AvlNode *t ) const
    {
        if( t != nullptr )
        {
	  printTree( t->left );
	  cout << t->element << endl;
	  printTree( t->right );
	}
    }

    /**
     * Return the height of node t or -1 if nullptr.
     */
    int height( AvlNode *t ) const
    {
        return t == nullptr ? -1 : t->height;
    }

    int max( int lhs, int rhs ) const
    {
        return lhs > rhs ? lhs : rhs;
    }

    /**
     * Rotate binary tree node with left child.
     * For AVL trees, this is a single rotation for case 1.
     * Update heights, then set new root.
     */
    void rotateWithLeftChild( AvlNode * & k2 )
    {
        AvlNode *k1 = k2->left;
        k2->left = k1->right;
        k1->right = k2;
        k2->height = max( height( k2->left ), height( k2->right ) ) + 1;
        k1->height = max( height( k1->left ), k2->height ) + 1;
        k2 = k1;
    }

    /**
     * Rotate binary tree node with right child.
     * For AVL trees, this is a single rotation for case 4.
     * Update heights, then set new root.
     */
    void rotateWithRightChild( AvlNode * & k1 )
    {
        AvlNode *k2 = k1->right;
        k1->right = k2->left;
        k2->left = k1;
        k1->height = max( height( k1->left ), height( k1->right ) ) + 1;
        k2->height = max( height( k2->right ), k1->height ) + 1;
        k1 = k2;
    }

    /**
     * Double rotate binary tree node: first left child.
     * with its right child; then node k3 with new left child.
     * For AVL trees, this is a double rotation for case 2.
     * Update heights, then set new root.
     */
    void doubleWithLeftChild( AvlNode * & k3 )
    {
        rotateWithRightChild( k3->left );
        rotateWithLeftChild( k3 );
    }

    /**
     * Double rotate binary tree node: first right child.
     * with its left child; then node k1 with new right child.
     * For AVL trees, this is a double rotation for case 3.
     * Update heights, then set new root.
     */
    void doubleWithRightChild( AvlNode * & k1 )
    {
        rotateWithLeftChild( k1->right );
        rotateWithRightChild( k1 );
    }
};

template <typename Comparable>
#define Infinity 30000
#define NegInfinity (-30000)
class SplayTree
{
 private:
  typedef int ElementType;
  typedef struct SplayNode *Tree;
  struct SplayNode
  {
    ElementType Element;
    Tree   Left;
    Tree   Right;
  };
 
  typedef struct SplayNode *Position;
  static Position NullNode = NULL;  /* Needs initialization */
 
  Tree InitializeSplayTree(void)
  {
    if (NullNode == NULL)
    {
        NullNode = malloc(sizeof(struct SplayNode));
        if (NullNode == NULL)
        {
            FatalError("Out of memory!!");
        }
        NullNode->Left = NullNode->Right = NullNode;
    }
    return NullNode;
  }
 
  static Tree Splay(ElementType Item, Position X);
 
  Tree MakeSplayTreeEmpty(Tree T)
  {
    if (T != NullNode)
    {
        MakeSplayTreeEmpty(T->Left);
        MakeSplayTreeEmpty(T->Right);
        free(T);
    }
    return NullNode;
  }
 
  void PrintTree(Tree T)
  {
    if (T != NullNode)
    {
        PrintTree(T->Left);
        printf("%d ", T->Element);
        PrintTree(T->Right);
    }
  }
 
  Tree FindInSplayTree(ElementType X,Tree T)
  {
    return Splay(X, T);
  }
 
  Tree FindMinInSplayTree(Tree T)
  {
    return Splay(NegInfinity, T);
  }
 
  Tree FindMaxInSplayTree(Tree T)
  {
    return Splay(Infinity, T);
  }
 
/*
 * This function can be called only if K2 has a left child.
 * Perform a rotate between a node (K2) and its left child.
 * Update heights, then return new root.
 */
  static Position SingleRotateWithLeft(Position K2)
  {
    Position K1;
 
    K1 = K2->Left;
    K2->Left = K1->Right;
    K1->Right = K2;
 
    return K1;  /* New root */
  }
 
/*
 * This function can be called only if K1 has a right child.
 * Perform a rotate between a node (K1) and its right child.
 * Update heights, then return new root.
 */
  static Position SingleRotateWithRight(Position K1)
  {
    Position K2;
 
    K2 = K1->Right;
    K1->Right = K2->Left;
    K2->Left = K1;
 
    return K2;  /* New root */
  }
 
/* Top-down splay procedure, not requiring item to be in tree. */
  SplayTree Splay(ElementType Item, Position X)
  {
    static struct SplayNode Header;
    Position LeftTreeMax, RightTreeMin;
 
    Header.Left = Header.Right = NullNode;
    LeftTreeMax = RightTreeMin = &Header;
    NullNode->Element = Item;
 
    while (Item != X->Element)
    {
        if (Item < X->Element)
        {
            if (Item < X->Left->Element)
            {
                X = SingleRotateWithLeft(X);
            }
            if (X->Left == NullNode)
            {
                break;
            }
 
            /* Link right */
            RightTreeMin->Left = X;
            RightTreeMin = X;
            X = X->Left;
        }
        else
        {
            if (Item > X->Right->Element)
            {
                X = SingleRotateWithRight(X);
            }
            if (X->Right == NullNode)
            {
                break;
            }
 
            /* Link left */
            LeftTreeMax->Right = X;
            LeftTreeMax = X;
            X = X->Right;
        }
    }
 
    /* Reassemble */
    LeftTreeMax->Right = X->Left;
    RightTreeMin->Left = X->Right;
    X->Left = Header.Right;
    X->Right = Header.Left;
 
    return X;
  }
 
  Tree insert(ElementType Item, Tree T)
  {
    static Position NewNode = NULL;
 
    if (NewNode == NULL)
    {
        NewNode = malloc(sizeof(struct SplayNode));
        if (NewNode == NULL)
        {
            FatalError("Out of memory!!");
        }
    }
    NewNode->Element = Item;
 
    if (T == NullNode)
    {
        NewNode->Left = NewNode->Right = NullNode;
        T = NewNode;
    }
    else
    {
        T = Splay(Item, T);
        if (Item < T->Element)
        {
            NewNode->Left = T->Left;
            NewNode->Right = T;
            T->Left = NullNode;
            T = NewNode;
        }
        else if (T->Element < Item)
        {
            NewNode->Right = T->Right;
            NewNode->Left = T;
            T->Right = NullNode;
            T = NewNode;
        }
        else
        {
            return T;  /* Already in the tree */
        }
    }
 
    NewNode = NULL;  /* So next insert will call malloc */
    return T;
  }
 
  Tree RemoveInSplayTree(ElementType Item, Tree T)
  {
    Position NewTree;
 
    if (T != NullNode)
    {
        T = Splay(Item, T);
        if (Item == T->Element)
        {
            /* Found it! */
            if (T->Left == NullNode)
            {
                NewTree = T->Right;
            }
            else
            {
                NewTree = T->Left;
                NewTree = Splay(Item, NewTree);
                NewTree->Right = T->Right;
            }
            free(T);
            T = NewTree;
        }
    }
 
    return T;
  }
 
  ElementType RetrieveInSplayTree(Tree T)
  {
    return T->Element;
  }
 public:
  Tree MakeSplayTreeEmpty(Tree T);
  Tree FindInSplayTree(ElementType X,Tree T);
  Tree FindMinInSplayTree(Tree T);
  Tree FindMaxInSplayTree(Tree T);
  Tree InitializeSplayTree(void);
  Tree insert(ElementType X, Tree T);
  Tree RemoveInSplayTree(ElementType X, Tree T);
  ElementType RetrieveInSplayTree(Tree T); 
};

#endif

